int rc;
op.cmd = EVTCHNOP_alloc_unbound;
- op.u.alloc_unbound.dom = (domid_t)dom;
-
+ op.u.alloc_unbound.dom = (domid_t)dom;
+ op.u.alloc_unbound.port = (port != NULL) ? *port : 0;
+
if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
{
if ( port != NULL )
XcObject *xc = (XcObject *)self;
u32 dom;
- int port;
+ int port = 0;
- static char *kwd_list[] = { "dom", NULL };
+ static char *kwd_list[] = { "dom", "port", NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
+ &dom, &port) )
return NULL;
if ( xc_evtchn_alloc_unbound(xc->xc_handle, dom, &port) != 0 )
#define evtchn_from_port(d,p) \
(&(bucket_from_port(d,p))[(p)&(EVTCHNS_PER_BUCKET-1)])
+#define ERROR_EXIT(_errno) do { rc = (_errno); goto out; } while ( 0 )
+
static int get_free_port(struct domain *d)
{
struct evtchn *chn;
{
struct evtchn *chn;
struct domain *d = current->domain;
- int port;
+ int port = alloc->port;
+ long rc = 0;
spin_lock(&d->evtchn_lock);
- if ( (port = get_free_port(d)) >= 0 )
+ /* Obtain, or ensure that we already have, a valid <port>. */
+ if ( port == 0 )
{
- chn = evtchn_from_port(d, port);
+ if ( (port = get_free_port(d)) < 0 )
+ ERROR_EXIT(port);
+ }
+ else if ( !port_is_valid(d, port) )
+ ERROR_EXIT(-EINVAL);
+ chn = evtchn_from_port(d, port);
+
+ /* Validate channel's current state. */
+ switch ( chn->state )
+ {
+ case ECS_FREE:
chn->state = ECS_UNBOUND;
chn->u.unbound.remote_domid = alloc->dom;
+ break;
+
+ case ECS_UNBOUND:
+ if ( chn->u.unbound.remote_domid != alloc->dom )
+ ERROR_EXIT(-EINVAL);
+ break;
+
+ default:
+ ERROR_EXIT(-EINVAL);
}
+ out:
spin_unlock(&d->evtchn_lock);
- if ( port < 0 )
- return port;
-
alloc->port = port;
- return 0;
+ return rc;
}
static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
{
-#define ERROR_EXIT(_errno) do { rc = (_errno); goto out; } while ( 0 )
struct evtchn *chn1, *chn2;
struct domain *d1, *d2;
int port1 = bind->port1, port2 = bind->port2;
bind->port2 = port2;
return rc;
-#undef ERROR_EXIT
}
#define __XEN_PUBLIC_EVENT_CHANNEL_H__
/*
- * EVTCHNOP_alloc_unbound: Allocate a fresh local port and prepare
- * it for binding to <dom>.
+ * EVTCHNOP_alloc_unbound: Prepare a local port for binding to <dom>.
+ * <port> may be wildcarded by setting to zero, in which case a fresh port
+ * will be allocated, and the field filled in on return.
*/
#define EVTCHNOP_alloc_unbound 6
typedef struct {
/* IN parameters */
domid_t dom; /* 0 */
u16 __pad;
- /* OUT parameters */
+ /* IN/OUT parameters */
u32 port; /* 4 */
} PACKED evtchn_alloc_unbound_t; /* 8 bytes */